package com.biz.primus.ms.commodity.service.backend.saleTag;

import com.biz.primus.base.exception.utils.AssertUtils;
import com.biz.primus.commodity.exception.CommodityExceptionType;
import com.biz.primus.commodity.vo.AddSaleTagProductVo;
import com.biz.primus.commodity.vo.SaleTagQueryVo;
import com.biz.primus.commodity.vo.backend.SaleTagListItemVo;
import com.biz.primus.commodity.vo.saleTag.SaleTagProductSearchReqVo;
import com.biz.primus.commodity.vo.saleTag.SaleTagProductSortReqVo;
import com.biz.primus.commodity.vo.saleTag.SaleTagSortProductVo;
import com.biz.primus.commodity.vo.saleTag.SaleTagVo;
import com.biz.primus.common.utils.DateUtil;
import com.biz.primus.common.vo.SpringPageVO;
import com.biz.primus.ms.base.service.AbstractBaseService;
import com.biz.primus.ms.base.vo.SpringPageToSpringPageVO;
import com.biz.primus.ms.commodity.dao.po.Product;
import com.biz.primus.ms.commodity.dao.po.SaleTag;
import com.biz.primus.ms.commodity.dao.redis.saleTag.SaleTagBackendRedisDao;
import com.biz.primus.ms.commodity.dao.redis.saleTag.SaleTagProductSortRedisDao;
import com.biz.primus.ms.commodity.dao.repository.product.ProductRepository;
import com.biz.primus.ms.commodity.dao.repository.saleTag.SaleTagRepository;
import com.biz.primus.ms.commodity.dao.ro.SaleTagProductRo;
import com.biz.primus.ms.commodity.dao.ro.SaleTagRo;
import com.biz.primus.ms.commodity.trans.SaleTag2SaleTagListItemVo;
import com.biz.primus.ms.commodity.trans.saleTag.SaleTag2SaleTagRo;
import com.biz.primus.ms.commodity.trans.saleTag.SaleTagRo2SaleTag;
import com.biz.primus.ms.commodity.trans.saleTag.SaleTagVo2SaleTag;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * Created by aaa on 2017/6/5.
 */
@Slf4j
@Service
public class SaleTagBackendService extends AbstractBaseService {

    @Autowired
    private SaleTagRepository saleTagRepository;

    @Autowired
    private SaleTagBackendRedisDao saleTagRedisDao;

    @Autowired
    private SaleTagProductSortRedisDao saleTagProductSortRedisDao;

    @Autowired
    private ProductRepository productRepository;

    @Transactional(rollbackFor = Exception.class)
    public void save(SaleTagVo vo) {
        SaleTag saleTag = null;
        if (StringUtils.isEmpty(vo.getId())) {
            log.info("create saleTage {}", vo);
            vo.setId(String.valueOf(idService.getNextId()));
            saleTag = new SaleTagVo2SaleTag().apply(vo);
        } else {
            log.info("update saleTage {}", vo);
            saleTag = saleTagRepository.findOne(Long.valueOf(vo.getId()));
            AssertUtils.notNull(saleTag, CommodityExceptionType.COMMON_EXCEPTION, "要修改的销售标签不存在");
            saleTag.setEditor(vo.getEditor());
            saleTag.setIdx(vo.getIdx());
            saleTag.setNote(vo.getNote());
            saleTag.setShowName(vo.getShowName());
            saleTag.setStatus(vo.getStatus());
            saleTag.setSubTag(vo.getSubTag());
            saleTag.setTag(vo.getTag());
            saleTag.setTagImage(vo.getTagImage());
            saleTag.setTagName(vo.getTagName());
        }
        saveOrUpdateUsingPo(saleTagRepository, saleTagRedisDao, saleTag, new SaleTag2SaleTagRo());
    }

    @Transactional(rollbackFor = Exception.class)
    public void delete(final Long id) {
        final SaleTagRo saleTagRo = saleTagRedisDao.findOne(id);
        if (saleTagRo != null) {
            final SaleTag saleTag = new SaleTagRo2SaleTag().apply(saleTagRo);
            saleTag.setDeleteFlag(true);
            saleTagRepository.save(saleTag);
            this.delayer.executeAfterTransactionCommit(() -> {
                saleTagRedisDao.delete(saleTagRo);
                saleTagProductSortRedisDao.deleteAllBySaleTag(id);
            });
        }

    }

    public SpringPageVO<SaleTagListItemVo> findAll(SaleTagQueryVo reqVo) {
        Page<SaleTag> saleTags = saleTagRepository.findAll(new Specification<SaleTag>() {
            @Override
            public Predicate toPredicate(Root<SaleTag> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                List<Predicate> predicates = Lists.newArrayList();
                criteriaQuery.orderBy(criteriaBuilder.desc(root.get("createTimestamp")));
                if (StringUtils.isNotBlank(reqVo.getName())) {
                    Predicate predicate = criteriaBuilder.like(root.get("tagName").as(String.class), "%" + reqVo.getName() + "%");
                    predicates.add(predicate);
                }
                criteriaQuery.where(predicates.toArray(new Predicate[predicates.size()]));
                return criteriaQuery.getRestriction();
            }
        }, reqVo.toPageRequest());
        return SpringPageToSpringPageVO.of(saleTags, new SaleTag2SaleTagListItemVo());
    }

    public SaleTagVo findOne(Long saleTagId) {
        SaleTag saleTag = saleTagRepository.findOne(saleTagId);
        SaleTagVo respVo = new SaleTagVo();
        respVo.setId(String.valueOf(saleTag.getId()));
        respVo.setTagName(saleTag.getTagName());
        respVo.setStatus(saleTag.getStatus());
        respVo.setCreateTime(saleTag.getCreateTimestamp());
        return respVo;
    }

    public void addProduct2SaleTag(AddSaleTagProductVo reqVo) {
        List<Product> products = productRepository.findByProductCodeIn(reqVo.getProductCodes());
        SaleTag saleTag = saleTagRepository.findOne(reqVo.getSaleTagIds());
        AssertUtils.notNull(saleTag, CommodityExceptionType.COMMON_EXCEPTION, "未找到销售标签");
        saleTag.setProducts(products);
        saleTagRepository.save(saleTag);
    }

    public void delProductSaleTag(String productCode, Long saleTagId) {
        Product product = productRepository.findByProductCode(productCode);
        SaleTag saleTag = saleTagRepository.findOne(saleTagId);
        product.getSaleTags().remove(saleTag);
        productRepository.save(product);
    }

    /**
     * 通过销售标签获取商品排序
     *
     * @param reqVo
     * @return
     */
    public List<SaleTagSortProductVo> findBySaleTag(SaleTagProductSearchReqVo reqVo) {
        final ArrayList<String> productCodes = Lists.newArrayList();
        final List<SaleTagProductRo> saleTagProductRos = saleTagProductSortRedisDao.findBySaleTag(reqVo);
        for (SaleTagProductRo saleTagProductRo : saleTagProductRos) {
            productCodes.add(saleTagProductRo.getProductCode());
        }
        return this.buildSaTagSortProductVos(productCodes, saleTagProductRos);
    }

    public int findTotalBySaleTag(SaleTagProductSearchReqVo reqVo) {
        return saleTagProductSortRedisDao.findTotalBySaleTag(reqVo);
    }


    /**
     * 获取销售标签和商品分类下的商品排序
     *
     * @param reqVo
     * @return
     */
    public List<SaleTagSortProductVo> findBySaleTagAndCategory(SaleTagProductSearchReqVo reqVo) {
        final List<String> productCodes = Lists.newArrayList();
        final List<SaleTagProductRo> saleTagProductRos = saleTagProductSortRedisDao.findBySaleTagAndCategory(reqVo);
        for (SaleTagProductRo saleTagProductRo : saleTagProductRos) {
            productCodes.add(saleTagProductRo.getProductCode());
        }
        return this.buildSaTagSortProductVos(productCodes, saleTagProductRos);
    }

    public int findTotalBySaleTagAndCategory(SaleTagProductSearchReqVo reqVo) {
        return saleTagProductSortRedisDao.findTotalBySaleTagAndCategory(reqVo);
    }

    public List<SaleTagSortProductVo> findByIds(List<String> ids) {
        final List<SaleTagProductRo> saleTagProductRos = saleTagProductSortRedisDao.findByIds(ids);
        final ArrayList<SaleTagSortProductVo> saleTagSortProductVos = Lists.newArrayList();
        for (SaleTagProductRo saleTagProductRo : saleTagProductRos) {
            SaleTagSortProductVo saleTagSortProductVo = new SaleTagSortProductVo();
            saleTagSortProductVo.setSaleTagId(saleTagProductRo.getSaleTagId());
            saleTagSortProductVo.setSort(saleTagProductRo.getSort() != null ? saleTagProductRo.getSort() : 9999);
            saleTagSortProductVo.setProductCode(saleTagProductRo.getProductCode());
            saleTagSortProductVos.add(saleTagSortProductVo);
        }
        return saleTagSortProductVos;
    }

    public void sort(SaleTagProductSortReqVo reqVo) {
        AssertUtils.hasText(reqVo.getProductCode(), CommodityExceptionType.COMMON_EXCEPTION, "商品编码不能为空");
        AssertUtils.notNull(reqVo.getSaleTagId(), CommodityExceptionType.COMMON_EXCEPTION, "销售标签id不能为空");
        AssertUtils.notNull(reqVo.getSort(), CommodityExceptionType.COMMON_EXCEPTION, "商品排序不能为空");
        String id = String.format("%s:%s", reqVo.getSaleTagId(), reqVo.getProductCode());
        SaleTagProductRo existsSaleTagProductRo = saleTagProductSortRedisDao.findOne(id);
        if (existsSaleTagProductRo != null) {
            existsSaleTagProductRo.setUpdateTimestamp(DateUtil.now());
            existsSaleTagProductRo.setSort(reqVo.getSort());
            saleTagProductSortRedisDao.save(existsSaleTagProductRo);
        } else {
            SaleTagProductRo saleTagProductRo = new SaleTagProductRo();
            final Product product = productRepository.findByProductCode(reqVo.getProductCode());
            AssertUtils.notNull(product, CommodityExceptionType.COMMON_EXCEPTION, "商品编码" + reqVo.getProductCode() + "没有对应的商品");
            saleTagProductRo.setId(id);
            saleTagProductRo.setProductCode(reqVo.getProductCode());
            saleTagProductRo.setSaleTagId(reqVo.getSaleTagId());
            saleTagProductRo.setSort(reqVo.getSort());
            saleTagProductRo.setCategoryId(product.getCategoryId());
            saleTagProductRo.setUpdateTimestamp(DateUtil.now());
            saleTagProductRo.setCreateTimestamp(DateUtil.now());
            saleTagProductSortRedisDao.save(saleTagProductRo);
            saleTagProductSortRedisDao.save(saleTagProductRo);
        }

    }


    private List<SaleTagSortProductVo> buildSaTagSortProductVos(List<String> productCodes, List<SaleTagProductRo> saleTagProductRos) {
        final ArrayList<SaleTagSortProductVo> saleTagProductVos = Lists.newArrayList();
        final List<Product> products = productRepository.findByProductCodeIn(productCodes);
        for (SaleTagProductRo saleTagProductRo : saleTagProductRos) {
            SaleTagSortProductVo saleTagProductVo = new SaleTagSortProductVo();
            saleTagProductVo.setProductCode(saleTagProductRo.getProductCode());
            saleTagProductVo.setSort(saleTagProductRo.getSort() != null ? saleTagProductRo.getSort() : 9999);
            saleTagProductVo.setSaleTagId(saleTagProductRo.getSaleTagId());
            for (Product product : products) {
                if (Objects.equals(product.getProductCode(), saleTagProductRo.getProductCode())) {
//                    saleTagProductVo.setCategoryName(product.getCategory().getName());
                    saleTagProductVo.setProductId(String.valueOf(product.getId()));
                    saleTagProductVo.setStatus(product.getSaleStatus());
                    saleTagProductVo.setProductName(product.getName());
                }
            }

        }
        return saleTagProductVos;
    }

}
